package utils;

import io.MessageWriter;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.io.Resources;

import sql.SqlExecutor;
import sql.SqlGenerator;
import sql.SqlGenerator.Response;
import config.Config;
import config.ConfigBuilder;
import entity.ColumnDefine;
import entity.IndexDefine;
import entity.PKColumnDefine;
import entity.SequenceDefine;
import entity.TableDefine;

public class DbMove {

    private SqlGenerator sqlGenerator;


    public DbMove() {
        InputStream inputStream;
        try {
            inputStream = Resources.getResourceAsStream("source.xml");
            ConfigBuilder builder = new ConfigBuilder(inputStream);

            Config config = builder.parse();

            sqlGenerator = new SqlGenerator(config);

        } catch (IOException e) {

            throw new RuntimeException();
        }
    }

    /**
     * 单表移动
     *
     * @param moveData 是否迁移数据
     */
    public void moveOneTable(boolean moveData, String tableName) {
        tableName = tableName.toUpperCase().trim();
        moveTableSchema(tableName);
        if (moveData) {
            moveData(tableName);
        }
    }

    /**
     * 全库移动
     *
     * @param moveData 是否迁移数据
     */
    public void dbmove(boolean moveData) {
        Response rep = sqlGenerator.genQueryTableSql();
        List<TableDefine> tables = SqlExecutor.getInstance().queryTables(rep.getSql());

        for (TableDefine table : tables) {
            moveTableSchema(table.getTableName());
            if (moveData) {
                moveData(table.getTableName());
            }
        }
    }

    /**
     * 生成全库建表SQL
     */
    public void genSql() {
        Response rep = sqlGenerator.genQueryTableSql();
        List<TableDefine> tables = SqlExecutor.getInstance().queryTables(rep.getSql());
        for (TableDefine table : tables) {
            moveTableSchema4Sql(table.getTableName());
        }
    }

    /**
     * 移动表结构，不包括数据
     *
     * @param tableName
     */
    public void moveTableSchema(String tableName) {
        if (tableName.startsWith("ACT") || tableName.startsWith("SYS_EXPORT_SCHEMA_01")) {
            MessageWriter.getInstance().writeWarning(String.format("%s：忽略", tableName));
            return;
        }

        MessageWriter.getInstance().writeInfo(String.format("开始迁移schema %s", tableName));

        MessageWriter.getInstance().writeInfo(String.format("%s：开始创建", tableName));

        Response rep = sqlGenerator.genQueryColumnsSql(tableName);
        MessageWriter.getInstance().writeWarning(tableName, rep);

        List<ColumnDefine> columns = SqlExecutor.getInstance().queryColumns(rep.getSql());

        List<String> sql4ColumnsDefine = new ArrayList<String>();
        for (ColumnDefine column : columns) {
            //处理每一列的数据
            rep = sqlGenerator.genCreateColumnDefineSql(column, tableName);
            MessageWriter.getInstance().writeWarning(tableName, rep);
            sql4ColumnsDefine.add(rep.getSql());
            if (column.getDataType().equals("XMLTYPE")) {
                IgnoreMvDataTable.add(tableName);
            }
        }

        rep = sqlGenerator.genCreateTableSql(tableName, StringUtils.join(sql4ColumnsDefine, ","));
        MessageWriter.getInstance().writeWarning(tableName, rep);
        SqlExecutor.getInstance().tryDropTable(tableName);
        SqlExecutor.getInstance().ddlOperator(rep.getSql());

        MessageWriter.getInstance().writeInfo(String.format("%s：创建成功", tableName));

        rep = sqlGenerator.genQueryIndexSql(tableName);
        MessageWriter.getInstance().writeWarning(tableName, rep);

        List<IndexDefine> indexs = SqlExecutor.getInstance().queryIndex(rep.getSql());

        if (indexs != null && indexs.size() > 0) {
            MessageWriter.getInstance().writeInfo(String.format("%s：开始创建索引", tableName));

            List<Response> reps = sqlGenerator.genCreateIndexSql(tableName, indexs);

            for (Response p : reps) {
                MessageWriter.getInstance().writeWarning(tableName, p);
                try {
                    SqlExecutor.getInstance().ddlOperator(p.getSql());
                } catch (Throwable e) {
                    MessageWriter.getInstance().writeWarning(String.format("%s索引%s创建失败", tableName, e.toString()));
                }
            }

            MessageWriter.getInstance().writeInfo(String.format("%s：开始创建索引完成", tableName));
        }

        rep = sqlGenerator.genQueryPkColumnsSql(tableName);
        MessageWriter.getInstance().writeWarning(tableName, rep);
        List<PKColumnDefine> pkColumns = SqlExecutor.getInstance().queryPkColumns(rep.getSql());
        if (pkColumns != null && pkColumns.size() > 0) {
            MessageWriter.getInstance().writeInfo(String.format("%s：开始创建主键", tableName));
            rep = sqlGenerator.genCreatePkConstraintSql(tableName, pkColumns);
            MessageWriter.getInstance().writeWarning(tableName, rep);
            SqlExecutor.getInstance().ddlOperator(rep.getSql());
            MessageWriter.getInstance().writeInfo(String.format("%s：开始创建主键完成", tableName));
        }

        MessageWriter.getInstance().writeInfo(String.format("schema 迁移完毕 %s", tableName));
    }

    /**
     * 生成表的建表语句
     *
     * @param tableName
     */
    public void moveTableSchema4Sql(String tableName) {
        if (tableName.startsWith("ACT") || tableName.startsWith("SYS_EXPORT_SCHEMA_01")) {
            MessageWriter.getInstance().writeWarning(String.format("%s：忽略", tableName));
            return;
        }

        MessageWriter.getInstance().writeInfo(String.format("开始迁移schema %s", tableName));

        MessageWriter.getInstance().writeInfo(String.format("%s：开始创建", tableName));

        Response rep = sqlGenerator.genQueryColumnsSql(tableName);
        MessageWriter.getInstance().writeWarning(tableName, rep);

        List<ColumnDefine> columns = SqlExecutor.getInstance().queryColumns(rep.getSql());

        StringBuilder sql4ColumnsDefine = new StringBuilder();
        for (int i = 0; i < columns.size(); i++) {
            ColumnDefine column = columns.get(i);
            rep = sqlGenerator.genCreateColumnDefineSql(column, tableName);
            MessageWriter.getInstance().writeWarning(tableName, rep);
            sql4ColumnsDefine.append("   " + rep.getSql());
            if (i < columns.size() - 1) {
                sql4ColumnsDefine.append(",");
            }
            sql4ColumnsDefine.append("\r\n");
        }

        rep = sqlGenerator.genCreateTableSql(tableName, "\r\n" + sql4ColumnsDefine);
        MessageWriter.getInstance().writeWarning(tableName, rep);
        MessageWriter.getInstance().writeSql(String.format("/*-----" + tableName + "-----*/"));
        MessageWriter.getInstance().writeSql(String.format("DROP TABLE IF EXISTS  %s", tableName));
        MessageWriter.getInstance().writeSql(rep.getSql());
        MessageWriter.getInstance().writeInfo(String.format("%s：创建成功", tableName));

        rep = sqlGenerator.genQueryIndexSql(tableName);
        MessageWriter.getInstance().writeWarning(tableName, rep);

        List<IndexDefine> indexs = SqlExecutor.getInstance().queryIndex(rep.getSql());

        if (indexs != null && indexs.size() > 0) {
            MessageWriter.getInstance().writeInfo(String.format("%s：开始创建索引", tableName));

            List<Response> reps = sqlGenerator.genCreateIndexSql(tableName, indexs);

            for (Response p : reps) {
                MessageWriter.getInstance().writeWarning(tableName, p);
                try {
                    MessageWriter.getInstance().writeSql(p.getSql());
                } catch (Throwable e) {
                    MessageWriter.getInstance().writeWarning(String.format("%s索引%s创建失败", tableName, e.toString()));
                }
            }

            MessageWriter.getInstance().writeInfo(String.format("%s：开始创建索引完成", tableName));
        }

        rep = sqlGenerator.genQueryPkColumnsSql(tableName);
        MessageWriter.getInstance().writeWarning(tableName, rep);
        List<PKColumnDefine> pkColumns = SqlExecutor.getInstance().queryPkColumns(rep.getSql());
        if (pkColumns != null && pkColumns.size() > 0) {
            MessageWriter.getInstance().writeInfo(String.format("%s：开始创建主键", tableName));
            rep = sqlGenerator.genCreatePkConstraintSql(tableName, pkColumns);
            MessageWriter.getInstance().writeWarning(tableName, rep);
            MessageWriter.getInstance().writeSql(rep.getSql());
            MessageWriter.getInstance().writeInfo(String.format("%s：开始创建主键完成", tableName));
        }


        MessageWriter.getInstance().writeInfo(String.format("schema 迁移完毕 %s", tableName));
    }

    /**
     * 移动表的数据
     *
     * @param tableName
     */
    public void moveData(String tableName) {
        if (IgnoreMvDataTable.ignore(tableName)) {
            MessageWriter.getInstance().writeWarning(String.format("%s表不支持数据迁移", tableName));
            return;
        }
        MessageWriter.getInstance().writeInfo(String.format("开始迁移数据%s", tableName));
        int pagesize = 1000;
        int currpage = 1;
        while (true) {
            int start = (currpage - 1) * pagesize;
            int end = currpage * pagesize;

            List<HashMap<String, Object>> datas = SqlExecutor.getInstance().loadData(tableName, null, start, end);
            if (datas != null && datas.size() > 0) {
                SqlExecutor.getInstance().insert(datas, tableName);
                if (datas.size() < pagesize) break;
            } else {
                break;
            }

            MessageWriter.getInstance().writeInfo(String.format("已迁移%d行数据", start + datas.size()));

            currpage++;
        }
        MessageWriter.getInstance().writeInfo(String.format("迁移数据完成%s", tableName));

    }

    public void moveSequence(String sequenceName) {
        Response rep = sqlGenerator.genQuerySequences();
        List<SequenceDefine> defines = SqlExecutor.getInstance().querySequence(rep.getSql());
        boolean sington = false;
        if (sequenceName != null && sequenceName.length() > 0) {
            sington = true;
        }

        for (SequenceDefine d : defines) {
            if (!sington || d.getsName().equals(sequenceName)) {
                try {
                    SqlExecutor.getInstance().ddlOperator("drop sequence " + d.getsName());
                } catch (Throwable e) {
                    //ignore
                }
                MessageWriter.getInstance().writeInfo(String.format("迁移序列%s", d.getsName()));
                SqlExecutor.getInstance().ddlOperator(d.getSql());
            }
        }

        MessageWriter.getInstance().writeInfo("序列迁移完毕");
    }
}
